<?php

/**
 * Store_PriceController
 * 
 * Модуль магазина, контроллер прайсов
 * В этом контроллере собраны методы для работы с ценами
 * 
 * @package   Store
 * @author    Игорь Будасов aka Lord <igor.budasov@gmail.com> 
 * @copyright Игорь Будасов aka Lord <igor.budasov@gmail.com> 
 */
 
class Store_PriceController extends Lord_Controller_Action 
{  
	
/*------------------------------------------------------------------------------*/

	/**
	* Индексный метод. 
	* Достает из базы все товары, приводит их к нужному виду,
	* генерит прайс и отдает юзеру
	*/
	
	public function indexAction()
	{
		// в имени файла у нас присутствует дата
		$file = 'content/store/prices_download/price_' . date('y_m_d') . '.xls';

		// если сегодня прайс уже генерили - отдадим готовый прайс юзеру
		if(is_file($file))
		{
		   $this->_sendFile($file);
		}
		// если сегодняшнего прайса нет - сделаем и отдадим
		else
		{
			// получаем список товаров, сортированый по группам и в шаблон                                                              
			$goods = $this->model->getAllGoods(); 
			// получаем экземпляр писалки 
			$writer = new Excel_Writer($file);
			// если какие-то товары есть
			if(!empty($goods))
			{
				// пишем заголовок файла
				$writer->writeHeader();
				// заголовок таблицы
				$writer->writeHead();
				// заполняем прайс
				foreach($goods as $good)
				{
					$writer->writeProduct($good);
				}
				// пишем подвал
				$writer->writeFooter();
			}
			// отдаем юзеру
			$this->_sendFile($file);
		}

		return;
	}

/*------------------------------------------------------------------------------*/
		 
	/**
	 * Парсер - это такая хитрая штука, которая парсит экселевский файл и 
	 * достает оттуда название товара и цену. Потом он проходит по базе и 
	 * обновляет цены и наличие у найденых товаров. Парсер призван облегчать 
	 * обновление цен в магазине. 
	 * Метод показывает формочку аплоада прайса и обрабатывает ее
	 */
	 
	public function parserAction()
	{
		// показываем форму
		$form = $this->_form();
		$this->view->form = $form; 
		// читаем конфиг
		$config = $this->_helper->config();	  
		
		if (!empty($_POST)) 
		{   
			// валидация 
			if (!$form->isValid($_POST)) 
			{   
				// показываем сообщение об ошибке
				$this->view->err = 'form_fail';
				// получаем невалидные значения, введенные в форму         
				$values = $form->getUnfilteredValues();
				// получаем ошибки
				$errors = $form->getErrors(); 
				// показываем форму с невалидными данными
				return $this->view->form = $this->_form($errors);
			}

			// обрабатываем форму
			if ($this->_request->isPost()) 
			{    
				// получаем корректные данные, введенные юзером
				$values = $form->getValues();
				
				/**
				* Перед всеми операциями с базой, давайте сделаем ее дамп.
				* Ну так, на всякий случай, всякое ведь бывает.
				*/
				$this->_makeDump();

				/**
				* Итак, у нас есть экселевский файл, с тремя колонками:
				* Название, Цена, Наличие.
				* Достанем из файла товары и приведем их к нужному виду
				*/

				// инстанцируем читалку
				$data = new Excel_Reader();
				// устанавливаем кодировку
				$data->setOutputEncoding($config->common->charset);
				// читаем 
				$data->read('content/store/prices/' . $values['file']);
				// общее количество полезных строк
				$countFoundGoods = 0;
				 
				// достаю товары из прайса
				for ($i = 1; $i <= $data->sheets[0]['numRows']; $i++) 
				{    
					// ячейки
					// костыль для ячейки с наличием
					$data->sheets[0]['cells'][$i][3] = 
						(!isset($data->sheets[0]['cells'][$i][3]))
						? 0
						: 1 ;
					 
					// если в строке 3 ячейки (Название, цена, наличие)
					if(count($data->sheets[0]['cells'][$i]) === 3)
					{
						// увеличиваем количество строк, в которых обнаружен товар
						$countFoundGoods = $countFoundGoods + 1;         
						// кладем в массив со всеми товарами
						$foundGoods[$countFoundGoods]['name']  = $data->sheets[0]['cells'][$i][1];
						$foundGoods[$countFoundGoods]['price'] = $data->sheets[0]['cells'][$i][2];
						$foundGoods[$countFoundGoods]['stock'] = $data->sheets[0]['cells'][$i][3];
					}
					// если в строке не 3 ячейки как нам нужно - удаляем ее
					else
					{
						unset($data->sheets[0]['cells'][$i]);
					}  
					
				}  
						 
				// привожу их к нужному виду. Должны остаться только букво-цифры и пробелы
				foreach($foundGoods as $k => $v)
				{
					$foundGoods[$k]['name']  = $this->_filter($v['name']);
					$foundGoods[$k]['price'] = $v['price'];
					$foundGoods[$k]['stock'] = $v['stock'];
				}
					
				/**
				* Теперь нам нужно достать товары из базы,
				* а также привести их к нужному виду
				*/
				
				// достаем все существующие товары из базы
				$existsGoods = $this->model->getAllGoods()->toArray();  
				// общее кол-во товаров совпадающих с прайсом. Их - на обработку
				$countExistsGoods = count($existsGoods);               
				// приведем существующие товары к нужному виду
				foreach($existsGoods as $key => $val)
				{                            
					$existsGoods[$key]['name'] = $this->_filter($val['name']);
				}                
				
				/**
				* Теперь, когда у нас есть два массива в нужном виде,
				* мы можем обновлять товары. Let's go!
				*/
				
                $updatedGoods = array();
				foreach($existsGoods as $eK => $existsGood)
				{
					foreach($foundGoods as $fK => $foundGood)
					{                        
						// обновляем товар
						$name  = (string)$foundGood['name'];
						$code  = (string)$existsGood['code']; 
						$found = stripos($name, $code);
						 
						if($found !== false)
						{
							$updatedGoods[] = $existsGood;
							// для того чтоб название товара не обновило - удаляем
							unset($foundGood['name']); 
							// обновляем товар           
							$this->model->updateGood($foundGood, $existsGood['id']);
							// товар нам больше не нужен, удаляем
							unset($foundGoods[$fK]);
						}
						
					}
				}            
					
				$newGoods = (!empty($foundGoods))
						  ? $foundGoods
						  : array();   
															 
				// передаем массивы с товарами в шаблон
				$this->view->existsGoods   = $existsGoods;
				$this->view->newGoods      = $newGoods;
				$this->view->foundGoods    = $foundGoods;
				$this->view->updatedGoods  = $updatedGoods;
				// чтоб заново не считать уже посчитаное - передаем количества
				$this->view->countUpdatedGoods = count($updatedGoods);
				$this->view->countNewGoods     = count($newGoods);
				$this->view->countExistsGoods  = $countExistsGoods;
				$this->view->countFoundGoods   = $countFoundGoods;
			}        
		} 
		return; 
	}

/*------------------------------------------------------------------------------*/

	/**
	* Метод для отображения прайс-листа
	*/

	public function viewAction()
	{                                   
		// получаем список товаров, сортированый по группам и в шаблон                                                              
		$goods = $this->model->getAllGoods();  

		// для каждого товара добавляем псевдо-поле с наличием картинки
		foreach($goods as $v)        
		{
			// картинки
			$image = $this->model->getMainImage($v['id']);
			 
			$images[$v['id']] = (!empty($image))
							  ? true
							  : false ;
		}
		
		// отправляем в шаблон
		$this->view->goods  = $goods;
		$this->view->images = $images;
		// возвращаемся
		return;
	}

/*==============================================================================*/
	
	/**
	* Приватный метод для построения формы
	* 
	* @param $errors array
	* @return object
	*/
	
	private function _form($errors = array())
	{
		// обратите внимание, форма создается на основе собственного класса. 
		$form = new Lord_Form_Form();
		$form->setAction( '/' . $this->_moduleName .
						  '/' . $this->_controllerName .
						  '/parser'
						 )
			 ->setMethod('post');
		
		// кодировка	 
		$charset = $this->_helper->config()->common->charset;
		
		// экселевский файл для загрузки
		$file = new Zend_Form_Element_File('file');
		$file->setLabel($this->view->translate('store_price_form_file'))
			   ->setDescription($this->view->translate('store_price_form_file_desc'))
			   // куда загружаем файл
			   ->setDestination('content/store/prices')
			   // ограничимся загрузкой одного файла
			   ->addValidator('Count', false, 1)
			   // поставим лимит в 900K
			   ->addValidator('Size', false, 921600)
			   // принимать будем только файлы с расширением XLS
			   ->addValidator('Extension', false, 'xls')
			   ->setRequired(true)
			   ;
		$form->addElement($file);			
		
		// кнопка сабмита	
		$form->addElement('submit', 'save', array('label' => $this->view->translate('store_price_form_submit')));
			
		// ошибки
		$this->_helper->FormErrors($errors, $form);
		
		return $form;
	}
	
/*------------------------------------------------------------------------------*/

	/**
	* Заменяет все символы кроме цифробукв на пробелы
	* 
	* @param string $str
	* @return string
	*/

	private function _filter($str = '')
	{
		$str = str_replace('(', ' ', $str);
		$str = str_replace(')', ' ', $str);
		$str = str_replace('-', ' ', $str);
		$str = str_replace('\\',' ', $str);
		$str = str_replace('/', ' ', $str);
		$str = str_replace('=', ' ', $str);
		$str = str_replace('+', ' ', $str);
		$str = str_replace('@', ' ', $str);
		$str = str_replace('!', ' ', $str);
		$str = str_replace('#', ' ', $str);
		$str = str_replace('$', ' ', $str);
		$str = str_replace('%', ' ', $str);
		$str = str_replace('^', ' ', $str);
		$str = str_replace('&', ' ', $str);
		$str = str_replace('*', ' ', $str);
		$str = str_replace('[', ' ', $str);
		$str = str_replace(']', ' ', $str);
		$str = str_replace('{', ' ', $str);
		$str = str_replace('}', ' ', $str);
		$str = str_replace(',', ' ', $str);
		$str = str_replace('.', ' ', $str);
		$str = str_replace(';', ' ', $str);
		$str = str_replace(':', ' ', $str);
		$str = str_replace('|', ' ', $str);
		return $str;
	}

/*------------------------------------------------------------------------------*/

	/**
	* Метод для установки такого хедера, который отдаст юзеру файл
    * КО сообщает, что такой метод отдачи файла называется "force download"
	* 
	* @param string $file
	*/

	private function _sendFile($file = '')
	{
		if (file_exists($file)) 
		{
			header('Content-Description: File Transfer');
			header('Content-Type: application/octet-stream');
			header('Content-Disposition: attachment; filename='.basename($file));
			header('Content-Transfer-Encoding: binary');
			header('Expires: 0');
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
			header('Pragma: public');
			header('Content-Length: ' . filesize($file));
			ob_clean();
			flush();
			readfile($file);
			exit;
		}  
		else    
		{
			return 0;
		}  
	}

/*------------------------------------------------------------------------------*/

    /**
    * Приватный метод для создания дампа базы
    */

    private function _makeDump()
    {
        $config = $this->_helper->config();
        // инстанцируем дампер
        $dumper = new MySQLDump();         
        // получаем из конфига название нашей БД
        $config = $this->_helper->config();
        $dataBase = $config->db->params->dbname;
        // получаем строку с дампом
        $dump = $dumper->dumpDatabase($dataBase, $config);
        // создаем файл для дампа
        $file = 'temporary/backup/base_dump_' . date('y_m_d') . '.sql';
        // если файл со свежим дампом уже есть - прекращаем работу функции
        if(is_file($file))
        {
            return;
        }
        // открываем файл
        if (!$handle = fopen($file, 'w+')) {
            // если не получилось открыть - прерываем процесс
            $this->view->err = $this->view->translate('store_price_makedump_fail');
            return;
        }
        // пишем в файл
        if (fwrite($handle, $dump) === FALSE) 
        {
            // если не получилось написать - прерываем процесс
            $this->view->err = $this->view->translate('store_price_makedump_fail');
            return;
        }
        // закрываем файл
        fclose($handle);
        // добавим информацию о файле в базу данных
        $date = date('Y-m-d G:i:s');
        $dumpData['date']        = $date;
        $dumpData['file']        = $file;
        $dumpData['filesize']    = filesize($file);
        $dumpData['description'] = $this->view->translate('store_price_makedump_restore_desc')
                                 . $date;
        $this->model->addDump($dumpData);
        return;
    }

/*------------------------------------------------------------------------------*/
}
